package com.bitcoin.scheduler.task;

import com.bitcoin.scheduler.domain.Bcc;
import com.bitcoin.scheduler.domain.BccBatch;
import com.bitcoin.scheduler.service.BccBatchService;
import com.bitcoin.scheduler.service.ServiceException;
import com.github.dozermapper.core.DozerBeanMapperBuilder;
import com.github.dozermapper.core.Mapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Slf4j
public abstract class AbstractCrawlTask implements Job {
    Mapper mapper = DozerBeanMapperBuilder.create()
        .withCustomConverter((source, target, aClass, aClass1) -> source != null ? source : target)
        .build();

    @Autowired
    BccBatchService batchService;

    @Override
    @Transactional
    public void execute(JobExecutionContext context) throws JobExecutionException {
        log.info("批次任务开始 Class {} ", getClass().getTypeName());
        //取得完成批次
        BccBatch batch = null;
        try {
            batch = getBatch(context.getMergedJobDataMap());
        } catch (ServiceException e) {
            log.warn(e.getMessage());
        }
        if (batch == null) {
            return;
        }
        try {
            //更新批次状态为处理中 flush db
            batch.setBatchState(Bcc.BathState.WASHING);
            batchService.getBatchDao().saveAndFlush(batch);
            log.info("批次任务更新批次状态为清洗中 批次号码 {} ", batch.getBatchNo());

            //处理批次详细数据到store
            saveBatchToStore(batch);
            log.info("处理批次详细数据到store完成 批次号码 {} ", batch.getBatchNo());
            //更新批次状态为处理完成
            batch.setBatchState(Bcc.BathState.HANDLE_DONE);
            batchService.getBatchDao().saveAndFlush(batch);
            log.info("处理批次详细数据到store完成 批次号码 {} ", batch.getBatchNo());
            //重新拉去数据缓存
            updateCache(batch);
            log.info("重新拉去数据缓存 批次号码 {} ", batch.getBatchNo());
        } catch (Exception e) {
            batch.setBatchState(Bcc.BathState.HANDLE_DONE);
            batchService.getBatchDao().saveAndFlush(batch);
            log.warn("批次任务执行异常 {} ", batch.getBatchNo());
            throw new JobExecutionException(e.getMessage(), e);
        }
    }

    /**
     * 处理批次详细数据到store
     *
     * @param batch 批次详细
     */
    protected abstract void saveBatchToStore(BccBatch batch) throws JobExecutionException;



    private BccBatch getBatch(JobDataMap dataMap) throws JobExecutionException, ServiceException {
        String batchNo = dataMap.getString("batchNo");
        BccBatch batch = null;
        if (StringUtils.isNotEmpty(batchNo)) {
            batch = batchService.getBatchDao().findByBatchNo(batchNo);
        }
        if (batch != null) {
            log.info("JobDataMap 取得批次");
        }
        else {
            List<BccBatch> batchList = batchService.getBatchDao().findByBatchTypeAndBatchStateOrderByEndDateDesc(getBatchType(), Bcc.BathState.HANDLE_DONE);
            if (!CollectionUtils.isEmpty(batchList)) {
                batch = batchList.get(0);
            }
            if (batch != null) {
                log.info("根据批次类型 {} 取得最新已爬完批次 {} ", getBatchType(), batch.getBatchNo());
            }
        }
        if (batch != null) {
            //批次类型必须匹配 批次状态必须为crawl_done
            if (!StringUtils.equals(batch.getBatchType(), getBatchType())) {
                throw new ServiceException("批次类型不匹配:批次号[{0}] 批次类型[{1}]  支持类型[{2}] ", batch.getBatchNo(), batch.getBatchType(), getBatchType());
            }
//            if (!StringUtils.equals(batch.getBatchState(), Bcc.BathState.handle_done)) {
//                throw new ServiceException("批次状态非CRAWL_DONE:批次号[{0}] 批次状态[{1}] ", batch.getBatchNo(), batch.getBatchState());
//            }
        }
        return batch;
    }

    /**
     * 重新拉去数据缓存
     */
    protected abstract void updateCache(BccBatch latestBatch);

    protected abstract String getBatchType();
}
